package com.panopset.gui.container;

import static com.panopset.Util.MONOSPACE_PLAIN_10;

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.Serializable;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.SortedSet;
import java.util.Stack;
import java.util.TreeSet;
import java.util.Map.Entry;

import javax.swing.JLabel;
import javax.swing.JMenu;
import javax.swing.JMenuBar;

import com.panopset.gui.TPanel;

/**
 *
 * @author Karl Dinwiddie
 *
 */
public abstract class Dropper<T extends Serializable> extends PanField<TPanel> {

    public String getSelection() {
        return getValue();
    }

    @Override
    public String getComponentValue() {
        return getSelectionLbl().getText();
    }

    @Override
    public void setComponentValue(String newValue) {
        getSelectionLbl().setText(newValue);
    }


    public abstract String getTopMenuName();

    public abstract String getMenuName(String key, int count);

    public abstract Map<String, T> getSelectionList();

    public abstract String getSelectionTipText(T selection);

    private ActionListener listener;
    private JMenuBar menuBar;

    public Dropper(final String title, final String defaultValue,
            final String tip) {
        super(title, tip, defaultValue);
    }

    @Override
    protected TPanel createComponent() {
        TPanel p = new TPanel();
        p.add(getSelectorPnl());
        p.add(getSelectionPnl());
        return p;
    }

    protected void alertNewSelection(T o) {
        // Override to do something when the user makes a selection.
    }

    private ActionListener getListener() {
        if (this.listener == null) {
            this.listener = new ActionListener() {

                @SuppressWarnings("unchecked")
                @Override
                public void actionPerformed(ActionEvent e) {
                    if (e.getSource() instanceof StorageMenuItem) {
                        StorageMenuItem<T> item = (StorageMenuItem<T>) e
                                .getSource();
                        getSelectionLbl().setText(item.getText());
                        alertNewSelection(item.itemStorage);
                    }
                }

            };
        }
        return this.listener;
    }

    private JMenuBar getMenuBar() {
        if (this.menuBar == null) {
            this.menuBar = new JMenuBar();
        }
        return this.menuBar;
    }

    public void refresh() {
        getMenuBar().removeAll();
        Map<String, Stack<StorageMenuItem<T>>> menus = new HashMap<String, Stack<StorageMenuItem<T>>>();
        int count = 0;
        for (String key : getSelectionList().keySet()) {
            final T val = getSelectionList().get(key);
            String menuName = getMenuName(key, count++);
            Stack<StorageMenuItem<T>> menuStack = menus.get(menuName);
            if (menuStack == null) {
                menuStack = new Stack<StorageMenuItem<T>>();
                menus.put(menuName, menuStack);
            }
            StorageMenuItem<T> mi = new StorageMenuItem<T>(val);
            mi.setFont(MONOSPACE_PLAIN_10);
            mi.setToolTipText(getSelectionTipText(getSelectionList().get(key)));
            mi.addActionListener(getListener());
            menuStack.push(mi);
        }
        JMenu valueMenu = new JMenu(getTopMenuName());
        valueMenu.setFont(MONOSPACE_PLAIN_10);
        getMenuBar().add(valueMenu);
        if (menus.size() >= 1) {
            if (menus.size() == 1) {
                for (Entry<String, Stack<StorageMenuItem<T>>> entry : menus.entrySet()) {
                    sortAndPopulate(valueMenu, entry.getValue());
                }
            } else {
                SortedSet<StorageMenuItem<JMenu>> set =
                    Collections.synchronizedSortedSet(new TreeSet<StorageMenuItem<JMenu>>());
                for (Entry<String, Stack<StorageMenuItem<T>>> entry : menus.entrySet()) {
                    JMenu subMenu = new JMenu(entry.getKey());
                    subMenu.setFont(MONOSPACE_PLAIN_10);
                    sortAndPopulate(subMenu, entry.getValue());
                    set.add(new StorageMenuItem<JMenu>(subMenu));
                }
                for (StorageMenuItem<JMenu> mi : set) {
                    valueMenu.add(mi.itemStorage);
                }
            }
        }
        getInnerComponent().invalidate();
        reset();
    }

    private void sortAndPopulate(JMenu menu, Stack<StorageMenuItem<T>> stack) {
        SortedSet<StorageMenuItem<T>> set =
            Collections.synchronizedSortedSet(new TreeSet<StorageMenuItem<T>>());

        while (!stack.isEmpty()) {
            set.add(stack.pop());
        }

        for (StorageMenuItem<T> mi : set) {
            menu.add(mi);
        }
    }

    private TPanel selectorPnl;

    private TPanel getSelectorPnl() {
        if (this.selectorPnl == null) {
            this.selectorPnl = new TPanel();
            refresh();
            this.selectorPnl.add(getMenuBar());
        }
        return this.selectorPnl;
    }

    private TPanel selectionPnl;

    private TPanel getSelectionPnl() {
        if (this.selectionPnl == null) {
            this.selectionPnl = new TPanel();
            this.selectionPnl.add(getSelectionLbl());
        }
        return this.selectionPnl;
    }

    private JLabel selectionLbl;

    private JLabel getSelectionLbl() {
        if (this.selectionLbl == null) {
            this.selectionLbl = new JLabel();
        }
        return this.selectionLbl;
    }

}
